#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include "targetParser.h"

using namespace std;

char line[300];
map<string, int> nonTerminal;

FILE *outF;
int tabCtrl = 0;
bool tmpTab = false;

void emitLn(string s) {
	if (s.length()>0 && s[0] == '}') --tabCtrl;
	for (int i=0; i<tabCtrl; ++i) fprintf_s(outF, "\t");
	if (tmpTab) {
		fprintf_s(outF, "\t");
		tmpTab = false;
	}
	fprintf_s(outF, "%s\n", s.c_str());
	if (s.length()>0) {
		char c = s[s.length()-1];
		if (c == '{') ++tabCtrl;
		else if (c == ')') tmpTab = true;
		
	}
}

void writeHead(void) {
	fopen_s(&outF, "targetParser.cpp", "w");
	emitLn("#include <iostream>");
	emitLn("#include <vector>");
	emitLn("#include <map>");
	emitLn("#include <string>");
	emitLn("#include <exception>");
	emitLn("#include <cstring>");
	emitLn("");
	emitLn("using namespace std;");
	emitLn("");
	emitLn("typedef struct TTerm {");
	emitLn("int type;");
	emitLn("string value;");
	emitLn("vector<TTerm> parts;");
	emitLn("} TTerm;");
	emitLn("");
	emitLn("class MyException : public exception {");
	emitLn("public:");
	emitLn("	string info;");
	emitLn("	string line;");
	emitLn("");
	emitLn("	virtual ~MyException(void) throw() {}");
	emitLn("};");
	emitLn("");
	emitLn("const int BNFWORD = 0;");
	for (map<string, int>::iterator it=nonTerminal.begin(); it!=nonTerminal.end(); ++it) {
		char buf[100];
		sprintf_s(buf, "const int %s = %d;", it->first.c_str(), it->second);
		emitLn(buf);
	}
	emitLn("");
	emitLn("string trim(string s) {");
	emitLn("int begin = s.find_first_not_of(\" \\t\\r\\n\");");
	emitLn("int end = s.find_last_not_of(\" \\t\\r\\n\");");
	emitLn("if (begin == -1) return \"\";");
	emitLn("return s.substr(begin, end+1-begin);");
	emitLn("}");
	emitLn("");
	emitLn("TTerm matchBNFWord(const string word, string& line){");
	emitLn("TTerm BNFWord;");
	emitLn("BNFWord.type = BNFWORD;");
	emitLn("");
	emitLn("if (line.length() < word.length()) {");
	emitLn("MyException e;");
	emitLn("e.info = \"too short line in BNFWord\";");
	emitLn("e.line = line;");
	emitLn("throw e;");
	emitLn("}");
	emitLn("for (unsigned int i=0; i<word.length(); ++i) {");
	emitLn("if (word[i] != line[i]) {");
	emitLn("MyException e;");
	emitLn("e.info = \"mismatch in BNFWord\";");
	emitLn("e.line = line;");
	emitLn("throw e;");
	emitLn("}");
	emitLn("}");
	emitLn("line = line.substr(word.length(), line.length()-word.length());");
	emitLn("BNFWord.value = word;");
	emitLn("");
	emitLn("return BNFWord;");
	emitLn("}");
	emitLn("");
	emitLn("void needSeparator(string& line) {");
	emitLn("if (line.length()>0 && line[0]!=' ') {");
	emitLn("MyException e;");
	emitLn("e.info = \"need separator\";");
	emitLn("e.line = line;");
	emitLn("throw e;");
	emitLn("}");
	emitLn("line = trim(line);");
	emitLn("}");
	emitLn("");
	for (map<string, int>::iterator it=nonTerminal.begin(); it!=nonTerminal.end(); ++it) {
		char buf[100];
		string s(it->first.c_str());
		transform(s.begin(), s.end(), s.begin(), ::tolower);
		sprintf_s(buf, "TTerm match_%s(string& line);", s.c_str());
		
		emitLn(buf);
	}
	emitLn("");
}

void writeFuncHead(string name) {
	string var = "_"+name;
	transform(var.begin(), var.end(), var.begin(), ::tolower);
	emitLn("TTerm match"+var+"(string& line) {");
	emitLn("TTerm "+var+";");
	emitLn("TTerm t;");
	emitLn(""+var+".type = "+name+";");
	emitLn("");
}
void writeFuncTail(string name) {
	string var = "_"+name;
	transform(var.begin(), var.end(), var.begin(), ::tolower);
	emitLn("return "+var+";");
	emitLn("}");
	emitLn("");
}

void writeMatchNT(string left, string name) {
	string var = "_"+name;
	transform(var.begin(), var.end(), var.begin(), ::tolower);
	
	emitLn("t = match"+var+"(line);");
	string leftVar = "_"+left;
	transform(leftVar.begin(), leftVar.end(), leftVar.begin(), ::tolower);
	emitLn(leftVar+".parts.push_back(t);");

	emitLn("");
}

string fixString(string s) {//add slash to escape char
	string tar = "";
	for (int i=0; i<s.length(); ++i) {
		if (s[i] == '"') {
			tar = tar + "\\" + s[i];
		}
		else tar = tar + s[i];
	}
	return tar;
}

void writeMatchBNFWord(string left, string name) {
	string leftVar = "_"+left;
	transform(leftVar.begin(), leftVar.end(), leftVar.begin(), ::tolower);
	emitLn("t = matchBNFWord(\""+fixString(name)+"\", line);");
	emitLn(leftVar+".parts.push_back(t);");
	emitLn("");
}

void writeOrBegin(string left, int depth) {
	string leftVar = "_"+left;
	transform(leftVar.begin(), leftVar.end(), leftVar.begin(), ::tolower);

	emitLn("if (hasErr) {");
	emitLn("hasErr = false;");
	{
		char buf[100];
		sprintf(buf, "%d", depth);
		string sd(buf);
		emitLn("line = bakLn["+sd+"];");
	}
	emitLn("bakParts = "+leftVar+".parts;");
	emitLn("try {");
}

void writeOrEnd(string left) {
	string leftVar = "_"+left;
	transform(leftVar.begin(), leftVar.end(), leftVar.begin(), ::tolower);
	emitLn("}");
	emitLn("catch(MyException e){");
	emitLn("hasErr = true;");
	emitLn("myE = e;");
	emitLn(leftVar+".parts = bakParts;");
	emitLn("}");
	emitLn("}");
	emitLn("");
}

void writeOrEndBegin(string left, int depth) {
	writeOrEnd(left);
	writeOrBegin(left, depth);
}

void writeThrowErr(string left, int depth) {
	emitLn("if (hasErr) {");
	{
		char buf[100];
		sprintf(buf, "%d", depth);
		string sd(buf);
		emitLn("line = bakLn["+sd+"];");
	}
	emitLn("myE.info = \"mismatch in "+left+"\";");
	emitLn("myE.line = line;");
	emitLn("throw myE;");
	emitLn("}");
}

void writeNeedSeparator(void) {
	emitLn("needSeparator(line);");
	emitLn("");
}

string trim2(string s) {
	int begin = s.find_first_not_of(" \t\r\n");
	int end = s.find_last_not_of(" \t\r\n");
	return s.substr(begin, end+1-begin);
}

string fixNT(string tar) {
	for (int i=0; i<tar.length(); ++i) {
		if (tar[i] == '_') continue;
		else if ('0' <= tar[i] && tar[i] <= '9') continue;
		else if ('A' <= tar[i] && tar[i] <= 'Z') continue;
		else if ('a' <= tar[i] && tar[i] <= 'z') continue;
		else tar[i] = '_';
	}
	return tar;
}

string getIdentifierName(string s) {
	s = fixNT(trim2(s));
	if (s[0]=='<') s = s.substr(1, s.length()-2);
	transform(s.begin(), s.end(), s.begin(), ::toupper);
	return s;
}

bool hasOr(string s) {
	int bc = 0;
	for (unsigned int i=0; i<s.length(); ++i)
		if (s[i] == '|') return true;
		else if (s[i] == '(') {
			++bc;
			for (i;i<s.length(); ++i) 
				if (s[i]==')') {
					--bc;
					if (bc == 0) break;
				}
		}
	return false;
}


//the writeMatch should add needSeparate parameter
void genFuncBody(string left, string right, int depth=0) {
	bool findOr = hasOr(right);
	if (findOr) {
		emitLn("hasErr = true;");
		char buf[100];
		sprintf(buf, "%d", depth);
		string sd(buf);
		emitLn("bakLn["+sd+"] = line;");
		writeOrBegin(left, depth);
	}

	for (unsigned int i=0; i<right.length(); ++i) {
		if (right[i] == '<') {
			int begin = i+1;
			for (++i;i<right.length();++i)
				if (right[i] == '>') break;
			int end = i;
			writeMatchNT(left, fixNT(right.substr(begin, end-begin)));
		}
		else if (right[i] == '[') {
			int begin = i+1;
			for (++i;i<right.length();++i)
				if (right[i] == ']') break;
			int end = i;
			writeMatchNT(left, fixNT(right.substr(begin, end-begin)));
		}
		else if (right[i] == '(') {
			int begin = i+1;
			int bc=0;
			for (;i<right.length(); ++i) {
				if (right[i]=='(') ++bc;
				else if (right[i] == ')') {
					--bc;
					if (bc == 0) break;
				}
			}
			int end = i;
			genFuncBody(left, right.substr(begin, end-begin), depth+1);
		}
		else if (right[i] == '"') {
			int begin=i+1;
			for (++i;i<right.length();++i) {
				if (right[i]=='"') break;
			}
			int end=i;
			writeMatchBNFWord(left, right.substr(begin,end-begin));
		}
		else if ('A'<=right[i] && right[i]<='Z') {
			int begin=i;
			for (;i<right.length(); ++i)
				if (right[i]==' ') break;
				else if (right[i] == '|') break;
			int end = i;
			writeMatchBNFWord(left, right.substr(begin,end-begin));
			if (i<right.length()) --i;
		}
		else if ('a'<=right[i] && right[i]<='z') {
			int begin=i;
			for (;i<right.length(); ++i)
				if (right[i]==' ') break;
				else if (right[i]=='_') continue;
				else if (right[i]<'a' || right[i]>'z') break;
			int end=i;
			writeMatchNT(left, fixNT(right.substr(begin, end-begin)));
			if (i<right.length()) --i;
		}
		else if (right[i] == '|') {
			writeOrEndBegin(left, depth);
		}
		else if (right[i] == ' ') {
			writeNeedSeparator();
			for (;i<right.length(); ++i)
				if (right[i] != ' ') break;
			if (i<right.length()) --i;
		}
		else if (right[i] == '\\') {
			++i;
			writeMatchBNFWord(left, right.substr(i,1));
		}
		else {
			int begin = i;
			for (;i<right.length(); ++i)
				if (right[i]==' ') break;
				else if ('a'<=right[i]&&right[i]<='z') break;
				else if (right[i] == '|') break;
			int end = i;
			writeMatchBNFWord(left, right.substr(begin,end-begin));
			if (i < right.length()) --i;
		}
	}

	if (findOr) {
		writeOrEnd(left);
		writeThrowErr(left, depth);
	}

}

void genCode(string line) {
	int pos = line.find("::=");
	string left = getIdentifierName(line.substr(0, pos));
	string right = trim2(line.substr(pos+3, line.length()-pos-3));

	writeFuncHead(left);
	if (right.find("|") != string::npos) {
		emitLn("bool hasErr = false;");
		emitLn("MyException myE;");
		emitLn("string bakLn[10];");
		emitLn("vector<TTerm> bakParts;");
		emitLn("");
	}


	genFuncBody(left, right);

	writeFuncTail(left);
}

int main0(void)
{
	ifstream inF;
	inF.open("input.txt");
	while (!inF.eof()) {
		inF.getline(line, 300);
		int beginPare = -1;
		for (unsigned int i=0; i<strlen(line); ++i) {
			if (line[i] == '<') {
				beginPare = i+1;
			}
			else if (line[i] == '>') {
				if (beginPare == -1) cout << "error parenthesis" << endl;
				string nt = string(line+beginPare, i-beginPare);
				transform(nt.begin(), nt.end(), nt.begin(), ::toupper);
				nonTerminal[nt] = 1;
			}
		}
	}

	int idx=1;
	for (map<string, int>::iterator it=nonTerminal.begin(); it!=nonTerminal.end(); ++it) {
		it->second = idx++;
		cout << it->first << " " << it->second << endl;
	}

	writeHead();

	inF.close();
	inF.open("input.txt");
	while (!inF.eof()) {
		inF.getline(line, 300);
		genCode(line);
	}

	return 0;
}

vector<string> dict;
bool notNT(string s) {
	if ('a'<=s[0]&&s[0]<='z') return false;
	return true;
}

int mainx(void)
{
	ifstream inF;
	inF.open("input.txt");
	while (!inF.eof()) {
		memset(line, 0, 300);
		inF.getline(line, 300);
		line[strlen(line)] = ' ';
		string sl(line);
		int pos = sl.find("::=");
		dict.push_back(getIdentifierName(sl.substr(0, pos)));
	}
	sort(dict.begin(), dict.end());
	dict.resize(unique(dict.begin(), dict.end())-dict.begin());
// 	dict.resize(remove_if(dict.begin(), dict.end(), notNT)-dict.begin());

	for (unsigned int i=0; i<dict.size(); ++i) {
// 		cout << dict[i] << endl;
		string tar=fixNT(dict[i]);
		transform(tar.begin(), tar.end(), tar.begin(), ::toupper);
		nonTerminal[tar] = 1;
	}

	int idx=1;
	for (map<string, int>::iterator it=nonTerminal.begin(); it!=nonTerminal.end(); ++it) {
		it->second = idx++;
		cout << it->first << " " << it->second << endl;
	}

	writeHead();

	inF.close();
	inF.open("input.txt");
	while (!inF.eof()) {
		inF.getline(line, 300);
		genCode(line);
	}


	return 0;
}